package com.example.petproject.service.third.WeChat;

import com.example.petproject.config.WeChatLoginConfig;
import com.example.petproject.constants.Constants;
import com.example.petproject.controller.UmsUserController;
import com.example.petproject.entity.model.UmsUser;
import com.example.petproject.entity.vo.ReturnStatusEnum;
import com.example.petproject.execption.BaseException;
import com.example.petproject.mapper.UmsUserMapper;
import com.example.petproject.util.ObjectMapperUtils;
import com.example.petproject.util.PetUmsUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 包名称：com.example.petproject.service.third.WeChat
 * 类名称：WeChatLoginService
 * 类描述：微信登录Service层实现
 * 创建人：@author DrinkMore-HotWater
 * 创建时间：2024年01月08日 11:13
 **/
@Service
public class WeChatLoginService {

    private static final Logger log = LoggerFactory.getLogger(WeChatLoginService.class);

    @Resource
    private WeChatLoginConfig weChatLoginConfig;

    /**
     * 发起请求，相当于浏览器
     */
    @Resource
    private RestTemplate restTemplate;

    @Resource
    private UmsUserMapper umsUserMapper;


    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private ObjectMapper objectMapper;

    /**
     * 微信登录后的回调，主要用于获取用户信息，并响应给前端
     *
     * @param wxCode 用户扫码确认后微信平台返回的code
     * @return 登录成功后的token
     */
    public String weChatLoginBack(String wxCode) {
        log.info("微信登录回调，wxCode:{}", wxCode);
        String token;
        try {
            //发起文档中的第二步请求，获取access_token
            String accessTokenUrl = generateAccessTokenUrl(wxCode);
            //发起请求并指定响应的数据类型
            String accessTokenJsonStr = restTemplate.getForObject(accessTokenUrl, String.class);
            Map accessTokenMap = objectMapper.readValue(accessTokenJsonStr, Map.class);

            //判断当前请求是否成功响应
            if (ObjectUtils.isEmpty(accessTokenMap) || !ObjectUtils.isEmpty(accessTokenMap.get("errorcode"))) {
                //表示当前响应结果纯在errorcode 节点，表示请求出现异常
                log.warn("微信登录获取access_token失败");
                throw new BaseException(ReturnStatusEnum.AUTH_WECHAT_LOGIN_FAIL);
            }
            String accessToken = accessTokenMap.get("access_token").toString();
            String openid = accessTokenMap.get("openid").toString();
            //在根据access_token获取用户信息,要判断当前用户在系统中是否存在，如果不存在将其存入数据库中
            String userInfoUrl = generateGetUserUrl(accessToken, openid);
            //根据openid从数据库查询用户信息，如果不存在，则需要先存入数据
            String userInfoResult = restTemplate.getForObject(userInfoUrl, String.class);
            Map userInfoMap = objectMapper.readValue(userInfoResult, Map.class);
            if (ObjectUtils.isEmpty(userInfoMap) || !ObjectUtils.isEmpty(userInfoMap.get("errorcode"))) {
                log.warn("微信登录获取用户信息失败");
                throw new BaseException(ReturnStatusEnum.AUTH_WECHAT_LOGIN_FAIL);
            }
            //验证数据库中的用户是否存在
            UmsUser wechatUser = umsUserMapper.selectUserByOpenId(openid);
            if (ObjectUtils.isEmpty(wechatUser)) {
                //将从微信响应的用户信息，存入数据库
                wechatUser = new UmsUser();
                wechatUser.setOpenid(openid);
                wechatUser.setHeadUrl(userInfoMap.get("headimgurl").toString());
                wechatUser.setUserName(userInfoMap.get("nickname").toString());
                wechatUser.setSex((Integer) userInfoMap.get("sex"));
                wechatUser.setUpdatedTime(LocalDateTime.now());
                wechatUser.setCreatedTime(LocalDateTime.now());
                umsUserMapper.insertSelective(wechatUser);
            }
            //生成token并将其存入redis，返回
            token = UUID.randomUUID().toString().replaceAll("-", "");
            String tokenRedisKey = PetUmsUtils.generateTokenRedisKey(token);

            stringRedisTemplate.opsForValue().set(tokenRedisKey, ObjectMapperUtils.objToString(wechatUser), Constants.Time.TOKEN_EFFECTIVE_TIME, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.warn("微信登录异常,", e);
            throw new BaseException(ReturnStatusEnum.SYSTEM_EXCEPTION);
        }
        return token;
    }

    /**
     * 生成获取 access_token 请求路径
     *
     * @param code 微信用户扫码确认后的返回的code
     * @return url
     */
    private String generateAccessTokenUrl(String code) {
        return new StringBuffer(weChatLoginConfig.getAccessTokenUrl())
                .append("?appId=").append(weChatLoginConfig.getAppId())
                .append("&secret=").append(weChatLoginConfig.getAppSecret())
                .append("&code=").append(code)
                .append("&grant_type=").append(weChatLoginConfig.getGrantType())
                .toString();
    }

    /**
     * 根据第二步中的accessToken获取用户信息路径
     * @param accessToken accessToken
     * @return url
     */
    private String generateGetUserUrl(String accessToken, String openid) {
        return new StringBuffer(weChatLoginConfig.getUserInfoUrl())
                .append("?access_token=").append(accessToken)
                .append("&openid=").append(openid)
                .append("%lang=").append(weChatLoginConfig.getLang())
                .toString();
    }
}
